package com.opengms.HydroModelsIntegration.service;

import com.ogms.modelservice.Data;
import com.ogms.modelservice.customer.RunModelService;
import com.opengms.HydroModelsIntegration.Config.IModelServiceConfig;
import com.opengms.HydroModelsIntegration.Config.MigratoryModelServiceConfig;
import com.opengms.HydroModelsIntegration.DTO.ModelServiceMigrationDTO;
import com.opengms.HydroModelsIntegration.Dao.*;
import com.opengms.HydroModelsIntegration.Config.ModelServiceConfig;
import com.opengms.HydroModelsIntegration.Domain.InpData;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.context.annotation.Import;
import org.springframework.core.io.support.PropertiesLoaderUtils;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpSession;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.UUID;

/**
 * @Author: David.Xiao
 * @Date: 2019/1/2 23:16
 * @Description:
 */
@Service
public class ModelService {



    /**
     * 全局配置文件的路径，已存在的模型服务
     */
    private final String modelServiceConfigPath = this.getClass().getResource("/").getPath()+"\\ModelService.properties";

    /**
     * 全局配置文件的路径，待迁移的模型服务
     */
    private final String migratoryModelServiceConfigPath = this.getClass().getResource("/").getPath()+"\\MigratoryModelService.properties";


    /**
     * 全局配置文件，已存在的模型服务信息
     */
    @Autowired
    @Qualifier(value = "modelServiceConfig")
    ModelServiceConfig modelServiceConfig;
    public ModelServiceConfig getModelServiceConfig() {
        return modelServiceConfig;
    }

    /**
     * 全局配置文件，待迁移的模型服务信息
     */
    @Autowired
    @Qualifier(value = "migratoryModelServiceConfig")
    MigratoryModelServiceConfig migratoryModelServiceConfig;
    public MigratoryModelServiceConfig getMigratoryModelServiceConfig() {
        return migratoryModelServiceConfig;
    }

    /**
     * 全局配置文件中的参数列表，已存在的模型服务
     */
    @Value("modelServiceConfig.urls")
    private List<String> globalUrls;
    private List<String> globalGuids;
    private List<String> globalWrapperIds;
    private List<String> globalPids;

    /**
     * 全局配置文件中的参数列表，待迁移的模型服务
     */
    private List<String> globalMigtatoryUrls;
    private List<String> globalMigtatoryGuids;
    private List<String> globalMigtatoryWrapperIds;
    private List<String> globalMigtatoryPids;

    /**
     * 用户私有的配置文件，已存在的模型服务信息
     */
    ModelServiceConfig pModelServiceConfig;
    public ModelServiceConfig getpModelServiceConfig() {
        return pModelServiceConfig;
    }

    /**
     * 用户私有的配置文件，待迁移的模型服务信息
     */
    MigratoryModelServiceConfig pMigratoryModelServiceConfig;
    public MigratoryModelServiceConfig getpMigratoryModelServiceConfig() {
        return pMigratoryModelServiceConfig;
    }

    /**
     * 全局配置文件，用户关心的模型服务匹配信息
     */
    private String enviroMatchFile;

    /**
     * 匹配信息json格式
     */
    private String enviroMatchJson;


    /**
     * 用户私有的工作文件夹的guid
     */
    private String userId;

    public String getUserId() {
        return userId;
    }

    /**
     * 用户私有的原始输入数据文件夹
     */
    private String pRawInputFile;

    /**
     * 用户私有的修正后的输入数据文件夹
     */
    private  String pModifiedInputFile;

    /**
     * 用户私有的输出数据文件夹
     */
    private  String pOutputDataFile;

    /**
     * 用户私有的配置文件的文件夹
     */
    private String pConfigFile;

    /**
     * 用户私有的原始输入数据全路径
     */
    private String pRawInputDataFullPath;

    /**
     * 用户私有的修正后的输入数据全路径
     */
    private String pModifiedInputDataFullPath;

    /**
     * 用户私有的输出数据文件全路径
     */
    private String pOutputDataFullPath;

    /**
     * 输出数据的urlList
     */
    private List<String> outputUrlList;

    /**
     * 输入数据json格式
     */
    private String inpJsonStr;

    /**
     * 输入的inp数据
     */
    private InpData inpData;

    /**
     * 用户选择的模型服务的id
     */
    private String modelServiceGuid;
    public void setModelServiceGuid(String modelServiceGuid) {
        this.modelServiceGuid = modelServiceGuid;
    }

    private String modelServiceWrapperId;

    public void setModelServiceWrapperId(String modelServiceWrapperId) {
        this.modelServiceWrapperId = modelServiceWrapperId;
    }

    /**
     * 用户选择的模型服务的url
     */
    private String modelServiceUrl;

    /**
     * 标志模型服务的配置文件是否已被读取
     */
    private boolean isModelServiceConfigLoaded;
    private boolean isModelMigratoryServiceConfigLoaded;




    public ModelService()
    {

        this.enviroMatchFile = new File(this.getClass().getResource("/").getPath()+"\\EnviroMatchConfig.json").getPath();
        this.enviroMatchJson = FileHelper.readJson(new File(enviroMatchFile));

        this.userId = UUID.randomUUID().toString();

        String pWorkPath = this.getClass().getResource("/").getPath()+"\\SwmmData" + "\\" + this.userId;
        this.pRawInputFile = pWorkPath + "\\RawInput";
        File rawInputFile=new File(this.pRawInputFile);
        if (!rawInputFile.exists())
        {
            rawInputFile.mkdirs();
        }

        this.pModifiedInputFile = pWorkPath + "\\ModifiedInput";
        File modifiedInput=new File(this.pModifiedInputFile);
        if (!modifiedInput.exists())
        {
            modifiedInput.mkdirs();
        }

        this.pOutputDataFile = pWorkPath + "\\Output";
        File output = new File(this.pOutputDataFile);
        if (!output.exists())
        {
            output.mkdirs();
        }

        //Copy全局配置文件到私人文件夹,已过时
        this.pConfigFile = pWorkPath + "\\config";
        File config = new File(this.pConfigFile);
        if (!config.exists())
        {
            config.mkdirs();
        }
        try {
            FileUtils.copyFileToDirectory(new File(modelServiceConfigPath),new File(pConfigFile));
            FileUtils.copyFileToDirectory(new File(migratoryModelServiceConfigPath),new File(pConfigFile));
        } catch (IOException e) {
            e.printStackTrace();
        }
        String pRelativeWorkPath = "SwmmData\\" + this.userId + "\\config\\ModelService.properties";
        this.isModelServiceConfigLoaded = false;
        this.isModelMigratoryServiceConfigLoaded = false;
        //------------------------------------------------------

    }


    public JSONArray getModelServicesInfo(Class clazz)
    {
        //初始化 将配置文件中的url，模型服务id，模型容器id读取到内存中，在后边操作时，只操作内存中的信息
        if(!isModelServiceConfigLoaded)
        {
            this.globalUrls = modelServiceConfig.getUrls();
            this.globalGuids = modelServiceConfig.getGuids();
            this.globalPids = modelServiceConfig.getPids();
            this.globalWrapperIds = modelServiceConfig.getWrapperIds();
            isModelServiceConfigLoaded = true;
        }
        if(!isModelMigratoryServiceConfigLoaded)
        {
            this.globalMigtatoryUrls = migratoryModelServiceConfig.getUrls();
            this.globalMigtatoryGuids = migratoryModelServiceConfig.getGuids();
            this.globalMigtatoryWrapperIds = migratoryModelServiceConfig.getWrapperIds();
            this.globalMigtatoryPids = migratoryModelServiceConfig.getPids();
            this.isModelMigratoryServiceConfigLoaded = true;
        }

        JSONArray newServiceInfoJsonArray = new JSONArray();
        int size = 0;
        if(clazz.isInstance(modelServiceConfig))
        {
            size = this.globalUrls.size();
        }
        else if (clazz.isInstance(migratoryModelServiceConfig))
        {
            size = this.globalMigtatoryUrls.size();
        }

        for (int index = 0;index < size;index++) {
            String url = this.globalUrls.get(index);
            String guid = this.globalGuids.get(index);
            String wrapperId = this.globalWrapperIds.get(index);
            if(clazz.isInstance(modelServiceConfig))
            {

                url = this.globalUrls.get(index);
                guid = this.globalGuids.get(index);
                wrapperId = this.globalWrapperIds.get(index);
            }
            else if (clazz.isInstance(migratoryModelServiceConfig))
            {
                url = this.globalMigtatoryUrls.get(index);
                guid = this.globalMigtatoryGuids.get(index);
                wrapperId = this.globalMigtatoryWrapperIds.get(index);
            }

            UrlHelper urlHelper = new UrlHelper("http://"+url+"/modelser/enviroMatch/portal");
            urlHelper.getConnection("POST");
            urlHelper.sendMessage(enviroMatchJson);
            String response = urlHelper.getResponse();
            urlHelper.closeConnection();
            JSONObject respConfigJsonArray = JSONObject.fromObject(response);
            JSONObject localConfigJsonObj = JSONObject.fromObject(enviroMatchJson);
            JSONObject newConfigJsonObject = new JSONObject();
            for (Object key:localConfigJsonObj.getJSONObject("data").keySet()) {
                newConfigJsonObject.put(key.toString(),traverseConfigs(localConfigJsonObj.getJSONObject("data").getJSONArray(key.toString()),respConfigJsonArray));
            }
            newConfigJsonObject.put("guid",guid);
            newConfigJsonObject.put("wrapperId",wrapperId);
            newServiceInfoJsonArray.add(newConfigJsonObject);
        }
        return newServiceInfoJsonArray;
    }

    private JSONArray traverseConfigs(JSONArray localConfigJsonArray,JSONObject respConfigJsonArray)
    {
        JsonHelper jsonHelper = new JsonHelper();
        JSONArray newConfigJsonArray = new JSONArray();

        for (Object object:localConfigJsonArray) {
            JSONObject newConfigObject = new JSONObject();
            String name = (String) ((JSONObject)object).get("name");

            jsonHelper.analysisJson(respConfigJsonArray,(obj)->{
                JSONArray jsonArray1 =  (JSONArray)obj;
                for (int j =0;j<jsonArray1.size();j++)
                {
                    JSONObject jsonObject2= (JSONObject) jsonArray1.get(j);
                    if((jsonObject2.get("title").toString()).equals(name))
                    {
                        for(int k = 0;k<((JSONArray)(jsonObject2.get("children"))).size();k++)
                        {
                            JSONObject jsonObject3 = (JSONObject)((JSONArray)(jsonObject2.get("children"))).get(k);

                            for (Object key:((JSONObject) object).keySet()) {
                                if(!key.equals("name") && jsonObject3.get("title").toString().equals(key.toString()))
                                {
                                    if(!newConfigObject.keySet().contains(name))
                                    {
                                        newConfigObject.put(name,jsonObject3.get("Value").toString());
//                                        System.out.println(name+"::"+jsonObject3.get("Value").toString());
                                    }

                                }
                            }

                        }
                    }
                }
            });
            newConfigJsonArray.add(newConfigObject);
        }
    return newConfigJsonArray;
    }

    public String setModelServiceMigration(ModelServiceMigrationDTO migrationDTO)
    {

        String sourceUrl = null;
        String sourceGuid = null;
        String sourcePid = null;

        for (int index = 0;index<this.globalUrls.size();index++) {
            if (this.globalWrapperIds.get(index).equals(migrationDTO.getFromWrapperId()))
            {
                sourceUrl = this.globalUrls.get(index);
                sourceGuid = this.globalGuids.get(index);
                sourcePid = this.globalPids.get(index);
            }
        }
        List<String> migratoryConfigUrls = this.globalMigtatoryUrls;
        List<String> migratoryConfigGuids = this.globalMigtatoryGuids;
        List<String> migratoryConfigWrapperIds = this.globalMigtatoryWrapperIds;
        String targetUrl = null;
        String targetGuid = null;
        String targetWrapperId = null;
        int indexToRemove=0;
        for (int index = 0;index<migratoryConfigUrls.size();index++) {
            if (migratoryConfigWrapperIds.get(index).equals(migrationDTO.getToWrapperId()))
            {
                targetUrl = migratoryConfigUrls.get(index);
                targetWrapperId = migratoryConfigWrapperIds.get(index);
                indexToRemove = index;
            }
        }
        if (sourceUrl!=null && sourcePid!=null && targetUrl!=null)
        {
            UrlHelper urlHelper = new UrlHelper("http://"+targetUrl+"/modelser/deployService/"+sourcePid + "?sourceId=" + sourceUrl);
            urlHelper.getConnection("GET");
            String response = urlHelper.getResponse();
            JSONObject respJson = JSONObject.fromObject(response);
            targetGuid =  ((JSONObject)respJson.get("data")).get("mid").toString();
            this.globalUrls.add(targetUrl);
            this.globalPids.add(sourcePid);
            this.globalGuids.add(targetGuid);
            this.globalWrapperIds.add(targetWrapperId);
            this.globalMigtatoryUrls.remove(indexToRemove);
            this.globalMigtatoryGuids.remove(indexToRemove);
            this.globalMigtatoryWrapperIds.remove(indexToRemove);
            this.globalMigtatoryPids.remove(indexToRemove);

            urlHelper.closeConnection();

            return "1";
        }
        return "0";
    }




    public String openFile(MultipartFile uploadFile)
    {
        this.pRawInputDataFullPath = this.pRawInputFile + "\\"+ uploadFile.getOriginalFilename();
        File localFile=new File(this.pRawInputDataFullPath);
        try {
            uploadFile.transferTo(localFile);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return uploadFile.getOriginalFilename();
    }

    public String parseInputData(String fileName)
    {
        //获得前台发来的文件名，判断后缀，如果是inp，直接解析；如果是xml，转为inp再解析
        String inpFileName = this.pRawInputDataFullPath;
        DataConverter dataConverter = new DataConverter();
        String convertedInputDataFullPath = this.pRawInputFile + "\\convertedInp.inp";
        if(fileName.endsWith(".xml"))
        {
            dataConverter.udx2Inp(this.pRawInputDataFullPath,convertedInputDataFullPath);
            inpFileName = convertedInputDataFullPath;
        }

        //解析inp数据
        InpParser inpParser = new InpParser();
        this.inpData = inpParser.parseInp(inpFileName);

        //转为json
        JSONObject jsonObject=JSONObject.fromObject(this.inpData);

        //获取geojson
        JSONObject geojsonObject=inpParser.getGeojsonFromInp();

        JSONObject object=new JSONObject();
        object.put("json",jsonObject);
        object.put("geojson",geojsonObject);
        System.out.println(geojsonObject.toString());
        this.inpJsonStr = object.toString();
        return this.inpJsonStr;
    }

    public JSONArray runModel(JSONObject inpJsonObj)
    {
        List<String> urls = modelServiceConfig.getUrls();
        List<String> guids = modelServiceConfig.getGuids();
        List<String> wrapperIds = modelServiceConfig.getWrapperIds();
        for (int index = 0;index<wrapperIds.size();index++)
        {//TODO 两次guid不是同一个guid
            if (wrapperIds.get(index).equals(this.modelServiceWrapperId))
            {
                this.modelServiceUrl = urls.get(index);
                this.modelServiceGuid = guids.get(index);

            }
        }
        String ip;
        String port;
        String[] strs = modelServiceUrl.split("://|:");
        ip = strs[0];
        port = strs[1];

        Json2Inp json2Inp =new Json2Inp();
        InpData inpData= json2Inp.json2InpData(inpJsonObj);

        //写入inp文件
        this.pModifiedInputDataFullPath = new File(this.pModifiedInputFile + "\\modifiedInput.inp").toString();

        InpWriter inpWriter =new InpWriter();
        inpWriter.inpData=inpData;
        inpWriter.writeInp(this.pModifiedInputDataFullPath);

        //跑模型
        RunModelService runModelService=new RunModelService(ip,port);
        Data pData=runModelService.uploadData(this.pModifiedInputDataFullPath);
        String recordId=runModelService.getRecordId(pData,this.modelServiceGuid);
        List<Data> outputDataList=runModelService.runModel(recordId);
        //获取输出数据的URL
        this.outputUrlList = runModelService.getOutputUrls(outputDataList);
        JSONArray urlJsonArray = JSONArray.fromObject(this.outputUrlList);

        return urlJsonArray;
    }

    public String downloadOutput2local()
    {

        for (String urlName:this.outputUrlList) {
            try {

                UrlHelper urlTools =new UrlHelper(urlName);
//                 folderName = urlName.substring(urlName.lastIndexOf("/")+1);
//                 this.setOutputDataPath(new File(getOutputDataFile() + "\\" + rptFileName).getPath());
                URL url = new URL(urlName);

                String fileName =  urlTools.getFileName();
                if(fileName.endsWith("rpt"))
                {
                    this.pOutputDataFullPath = this.pOutputDataFile + "\\" + fileName;
                    File file = new File(this.pOutputDataFullPath);
                    if(!FileHelper.pathExists(new File(this.pOutputDataFile)))
                    {
                        return null;
                    }
                    FileUtils.copyURLToFile(url,file);
                }

            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return this.pOutputDataFullPath;
    }


    public String parseOutputData()
    {

        DataConverter dataConverter = new DataConverter();

        String rptFileFullPath = downloadOutput2local();
        String udxFileFullPath = this.pOutputDataFile + "\\SwmmModel-rptData.xml";
        dataConverter.rpt2Udx(rptFileFullPath,udxFileFullPath);

        return FileHelper.readXml(new File(udxFileFullPath));
    }

    public JSONArray makeTree(JSONArray jsonArray)
    {
        TreeDataMaker treeDataMaker = new TreeDataMaker(this.inpData,jsonArray);
        return treeDataMaker.makeTreeData(jsonArray);
    }

    public String readOutputSchema()
    {
        return FileHelper.readXml(new File(this.getClass().getResource("/").getPath()+"\\OutputSchema.xml"));
    }

    public String readUdxData()
    {
        String str = parseOutputData();
//         String str = FileHelper.readXml(new File(this.getClass().getResource("/").getPath()+"\\1c2133d1-48e3-498f-bc69-49fea34cf06b.xml"));
        return str;
    }

    public String readInputSchema()
    {
        return FileHelper.readXml(new File(this.getClass().getResource("/").getPath()+"\\InputSchema.xml"));
    }



    private ModelServiceConfig getPModelServiceAddressConfig()
    {
        String aaa;
        try {
            aaa = this.pConfigFile+"\\ModelService.properties";
            Properties properties =  PropertiesLoaderUtils.loadAllProperties(this.getClass().getResource("/").getPath()+"\\"+this.userId+"\\ModelService.properties");
            modelServiceConfig.setGuids((List<String>)properties.get("model-service.guids"));
        } catch (IOException e) {
            e.printStackTrace();
        }
        return modelServiceConfig;
    }


}
